package cool.xinya.ess.security;

import cool.xinya.ess.dao.TSysUserMapper;
import cool.xinya.ess.util.DateUtil;
import cool.xinya.ess.util.SessionUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.Collection;

public class UserRealm extends AuthorizingRealm {
    @Resource
    private TSysUserMapper userMapper;
    @Autowired
    private DefaultWebSessionManager sessionManager;
    @Autowired
    @Lazy
    private DefaultWebSecurityManager securityManager;

    /**
     * Shiro登录认证(原理：用户提交 用户名和密码
     * ---- realm 通过用户名将密码查询返回
     * ---- shiro 自动去比较查询出密码和用户输入密码是否一致
     * ---- 进行登陆控制 )
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 判断用户是否存在
        String username = token.getPrincipal().toString();
        ShiroUser user = userMapper.selectByName(username);
        if (user == null) {
            throw new IncorrectCredentialsException();
        }
        if (user.getStatus() == 0) {
            throw new AuthenticationException("该用户为无效用户");
        }
        if (DateUtil.getCurrentTime().getTime() - user.getExpireTime().getTime() > 0) {
            throw new AuthenticationException("该用户为过期用户");
        }
        String remoteHost = SessionUtil.getHttpServletRequest().getRemoteHost();
        if (!StringUtils.isEmpty(user.getBindIp()) && !remoteHost.equals(user.getBindIp())) {
            throw new AuthenticationException("该用户设置了IP登录");
        }
        // 用户重复登录限制,登陆时会把之前已登录的同一用户session清除
        Collection<Session> sessionList = sessionManager.getSessionDAO().getActiveSessions();
        if (!CollectionUtils.isEmpty(sessionList)) {
            try {
                for (Session session : sessionList) {
                    ShiroUser shiroUser = (ShiroUser) new Subject.Builder(securityManager).session(session).buildSubject().getPrincipal();
                    if (shiroUser != null) {
                        String sessionId = (String) session.getId();
                        if (StringUtils.isEmpty(sessionId)) {
                            throw new RuntimeException("用户已在其他设备登录");
                        }
                        String subjectId = (String) SecurityUtils.getSubject().getSession().getId();
                        if (!StringUtils.isEmpty(shiroUser.getLoginName()) && shiroUser.getLoginName().equals(username)
                                && !sessionId.equals(subjectId)) {
                            break;
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 认证信息
        return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
    }

    /**
     * Shiro访问授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return new SimpleAuthorizationInfo();
    }
}